// Fill out your copyright notice in the Description page of Project Settings.


#include "UserWidget/WidgetComponent/SingleObjectiveWidget.h"
#include "Components/Border.h"
#include "Components/TextBlock.h"
#include "Components/ProgressBar.h"
#include "Components/SizeBox.h"
#include "Kismet/KismetMathLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "Libraries/CommonLibrary.h"

#define LOCTEXT_NAMESPACE "BulletScars_Mission"

void USingleObjectiveWidget::NativeConstruct() {
	Super::NativeConstruct();
	ESlateVisibility InVisibility= ESlateVisibility::Collapsed;
	switch (ObjectiveInfo.ObjectiveClass)
	{
		case EObjectiveLType::Select:
		case EObjectiveLType::SingleTarget:
			InVisibility = ESlateVisibility::Collapsed;
			break;
		case EObjectiveLType::MultipleTargets:
			InVisibility = ESlateVisibility::SelfHitTestInvisible;
			break;
	}
	ProgressBarFrame->SetVisibility(InVisibility);
	ObjectiveTitle->SetText(ObjectiveInfo.ObjectiveLayout.ObjectiveTitle);
	MaxInProgress = CalculateAmount(Targets);
	AmountText->SetText(FText::Format(LOCTEXT("Current/Max", "{0}/{1}"), FText::AsNumber(CurrentInProgress), FText::AsNumber(MaxInProgress)));
	Completed = false;
}

void USingleObjectiveWidget::NativeOnInitialized() {
	Super::NativeOnInitialized();
	CurrentInProgress = 0.f;
	MaxInProgress = 0.f;
	NewProgress = 0.f;
	ToAdd = 1;
	Completed = false;
	AddedAmount = 0;
}

void USingleObjectiveWidget::ContructWidget(FObjectives LObjectiveInfo) {
	ObjectiveInfo = LObjectiveInfo;
}

void USingleObjectiveWidget::ToggleSingleObjective(EToggleVisibility LVisibility) {
	EUMGSequencePlayMode::Type PlayMode = EUMGSequencePlayMode::Forward;
	switch (LVisibility)
	{
	case EToggleVisibility::Visible:
		PlayMode = EUMGSequencePlayMode::Forward;
		break;
	case EToggleVisibility::Hidden:
		PlayMode = EUMGSequencePlayMode::Reverse;
		break;
	}
	PlayAnimation(UCommonLibrary::GetAnimInstance(GetClass(), FText::FromString("Slide")), 0.f, 1.f, PlayMode);

}

void USingleObjectiveWidget::UpdateAsCompleted(){
	InnerFrame->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
	Completed = true;
}

float USingleObjectiveWidget::InProgress(){
	//float Value, float RangeMin, float RangeMax
	return UKismetMathLibrary::NormalizeToRange(CurrentInProgress, 0.f, MaxInProgress);
}

void USingleObjectiveWidget::LerpProgress(){
	CurrentInProgress = UKismetMathLibrary::FInterpTo_Constant(CurrentInProgress, NewProgress, UGameplayStatics::GetWorldDeltaSeconds(this), 2.f);
	if (CurrentInProgress == NewProgress) {
		GetWorld()->GetTimerManager().ClearTimer(LerpTimer);
	}
}

int32 USingleObjectiveWidget::CalculateAmount(TArray<FAssignedObjectiveTarget> InArray){
	int32 Result = 0;
	for (int32 i = 0; i < InArray.Num(); ++i) {
		Result += InArray[i].Amount;
	}
	return Result;
}

void USingleObjectiveWidget::IncreaseAssignedTarget(TSubclassOf<AActor> Class, int32 Amount){
	for (int32 i = 0; i < Targets.Num(); ++i) {
		//DEBUG_MESSAGE("IncreaseAssignedTarget");
		if (Class == Targets[i].TargetClass) {
			FAssignedObjectiveTarget Temp;
			Temp.UniqueNameMatters = true;
			Temp.UniqueName = FName();
			Temp.TargetClass = Class;
			Temp.Amount += Amount;
			Targets[i] = Temp;
		}
	}
}

void USingleObjectiveWidget::AddOrIncreaseTarget(FAssignedObjectiveTarget ObjectiveTarget) {
	bool Contains=false;
	int32 Amount=0;
	ContainsInTargets(ObjectiveTarget, Contains, Amount);
	if (Contains) {
		//DEBUG_MESSAGE("AddOrIncreaseTarget");
		IncreaseAssignedTarget(ObjectiveTarget.TargetClass, ObjectiveTarget.Amount);
	}
	else {
		Targets.Add(ObjectiveTarget);
	}
	//DEBUG_MESSAGE("AddOrIncreaseTarget:%i", Targets.Num());
}

void USingleObjectiveWidget::ContainsInTargets(FAssignedObjectiveTarget ObjectiveTarget, bool& Contains, int32 Amount){
	//DEBUG_MESSAGE("ContainsInTargets:%i", Targets.Num());
	for (int32 i = 0; i < Targets.Num(); ++i) {
		bool temp;
		if (ObjectiveTarget.UniqueNameMatters) {
			temp = ObjectiveTarget.UniqueName == Targets[i].UniqueName;
		}
		else {
			temp = ObjectiveTarget.TargetClass == Targets[i].TargetClass;
		}
		if (temp) {
			Contains = true;
			Amount = Targets[i].Amount;
			break;
		}
		else {
			Contains = false;
			Amount = 0;
		}
	}
}

void USingleObjectiveWidget::CountAddedAmount(int32 Add){
	AddedAmount = FMath::Clamp(AddedAmount + Add, 0, UKismetMathLibrary::FTrunc(MaxInProgress));
	ToAdd += Add;
}

void USingleObjectiveWidget::UpdateProgressText(){
	NewProgress = FMath::CeilToFloat(FMath::Clamp(CurrentInProgress + ToAdd, 0.f, MaxInProgress));
	AmountText->SetText(FText::Format(LOCTEXT("Current/Max", "{0}/{1}"), FText::AsNumber(FMath::Clamp(NewProgress, 0.f, MaxInProgress)), FText::AsNumber(MaxInProgress)));
}

int32 USingleObjectiveWidget::FindInTargets(FAssignedObjectiveTarget ObjectiveTarget){
	if (Targets.Num() != 0) {
		bool Contains=false;
		int32 Amount=0;
		ContainsInTargets(ObjectiveTarget, Contains, Amount);
		if (Contains) {
			return Amount + 1;
		}
	}
	return 0;
	
	
}

void USingleObjectiveWidget::AddProgress(FAssignedObjectiveTarget ObjectiveTarget){
	CountAddedAmount(ObjectiveTarget.Amount);
	UpdateProgressText();
	FTimerDelegate RespawnDelegate = FTimerDelegate::CreateUObject(this, &USingleObjectiveWidget::DelayLater);
	GetWorld()->GetTimerManager().SetTimer(LoopTimer, RespawnDelegate, 0.1f, true);
}

void USingleObjectiveWidget::DelayLater() {
	if (GetWorld()->GetTimerManager().IsTimerActive(LerpTimer)) {
		return;
	}
	GetWorld()->GetTimerManager().ClearTimer(LoopTimer);
	FTimerDelegate RespawnDelegate = FTimerDelegate::CreateUObject(this, &USingleObjectiveWidget::LerpProgress);
	ToAdd = 0;
	GetWorld()->GetTimerManager().SetTimer(LerpTimer, RespawnDelegate, 0.01f, true);	
}

#undef LOCTEXT_NAMESPACE